unit uMainFrm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,

  GlScene, GlObjects, GlCadencer, GLWin32Viewer, GLRenderContextInfo, GlWindowsFont, GlHudObjects,
  GlMaterial,
  VectorGeometry,
  uTweener;
const
  MatNames: array [1..4] of String = ('top', 'left', 'right', 'bottom');  
type
  TfrmMain = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    {Main Objects}
    fGlScene: TGlScene;
    fCadencer: TGLCadencer;
    fViewer: TGLSceneViewer;
    fCamera: TGlCamera;
    fMainDummy: TGlDummyCube;
    fFpsTimer: Single;
    fMatLib: TGlMaterialLibrary;

    {Text Objects}
    fWinFont: TGLWindowsBitmapFont;
    fHudText: TGLHUDText;
    fHudSprites: array[1..4] of TGlHudSprite;
    fBack: TGlHudSprite;

    {Tween-objects}
    fTweener: TTweener;
    TweenNext: Integer;
    Pos: array[1..4] of TVector;

    MousePressed: Boolean;
  public
    Procedure InitFontAndSprites;
    Procedure InitMaterials;
    Procedure InitTweener;
    Function  GetHudSpriteAtPos(x, y: integer): Integer;
    Procedure StartTween(aType: Integer);
    Procedure OnCadencerProgress(Sender : TObject; const deltaTime, newTime : Double);
  end;

var
  frmMain: TfrmMain;

implementation
uses
  glKeyboard,
  uDemoInit;
{$R *.dfm}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  fFpsTimer := 0;
  CreateDemo(self, fGlScene, fCadencer, fViewer);
  
  fCamera := TGlCamera.CreateAsChild(fGlScene.Objects);
  with fCamera do
  begin
    Position.SetPoint(0, 0, 5);
    Direction.SetVector(0, 0, -1);
    Up.SetVector(0, 1, 0);
    CameraStyle := csOrthogonal;
    SceneScale := 0.1;
  end;

  fMainDummy := TGLDummyCube.CreateAsChild(fGlScene.Objects);
  fMainDummy.ObjectsSorting := osNone;

  fViewer.Camera := fCamera;
  fCadencer.OnProgress := OnCadencerProgress;

  fMatLib := TGlMaterialLibrary.Create(self);

  InitMaterials;
  InitFontAndSprites;
  InitTweener;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  FreeAndNil(fTweener);
end;

procedure TfrmMain.FormActivate(Sender: TObject);
begin
  fCadencer.Enabled := true;
end;

Procedure TfrmMain.InitFontAndSprites;
var
  i: integer;
begin
  fWinFont := TGLWindowsBitmapFont.Create(self);
  fWinFont.Font.Name := 'Arial';

  fBack := TGlHudSprite.CreateAsChild(fMainDummy);
  with fBack do
  begin
    Material.LibMaterialName := 'back';
    Material.MaterialLibrary := fMatLib;
    Width := Material.GetActualPrimaryTexture.Image.Width;
    Height := Material.GetActualPrimaryTexture.Image.Height;
    Position.SetPoint(Width / 2, Height / 2, 0);
  end;

  fHudText := TGLHUDText.CreateAsChild(fMainDummy);
  with fHudText do
  begin
    BitmapFont := fWinFont;
    Text := 'Lampogolovii presents ''Tweener Demo''';
    Position.SetPoint(390, 380, 0);
    Alignment := taRightJustify;
  end;
  
  for i := 1 to 4 do
  begin
    fHudSprites[i] := TGlHudSprite.CreateAsChild(fMainDummy);
    with fHudSprites[i] do
    begin
      Material.LibMaterialName := MatNames[i];
      Material.MaterialLibrary := fMatLib;
      Width := Material.GetActualPrimaryTexture.Image.Width;
      Height := Material.GetActualPrimaryTexture.Image.Height;
    end;
  end;
end;

Procedure TfrmMain.InitMaterials;
begin
  AddMaterials(fMatLib, str_ImagesFolder + '\TweenerDemo\', ['left.png', 'top.png', 'right.png', 'bottom.png'], MatNames);
  AddMaterial(fMatLib, str_ImagesFolder + '\TweenerDemo\back.jpg', 'back');
end;

Procedure TfrmMain.InitTweener;
begin
  MousePressed := false;
  fTweener := TTweener.Create;
  StartTween(1);
end;

Function  TfrmMain.GetHudSpriteAtPos(x, y: Integer): Integer;
var
  i: integer;
begin
  result := -1;
  for i := 1 to 4 do
    with fHudSprites[i] do
      if (x > Position.X - Width/2)  and (x < Position.X + Width/2)
      and(y > Position.Y - Height/2) and (y < Position.Y + Height/2)then
        result := i;
end;

Procedure TfrmMain.StartTween(aType: Integer);
var
  i: integer;
  x1, y1, x2, y2: integer;
  Procedure SetXY(ax1, ay1, ax2, ay2: integer);
  begin
    x1 := ax1;
    y1 := ay1;
    x2 := ax2;
    y2 := ay2;
  end;
begin
  TweenNext := aType;
  with fTweener do
  begin
    if(aType = 1) then
      SetXY(-200, 0, 100, 0)
    else if(aType = 2) then
      SetXY(0, -100, 0, 50)
    else if(aType = 3) then
      SetXY(fViewer.Width + 200, 0, fViewer.Width - 100, 0)
    else if(aType = 4) then
      SetXY(0, fViewer.Height + 100, 0, fViewer.Height - 50);

    if(aType = 1) or (aType = 3) then
      for i := 1 to 4 do
        AddTweenPVector(@Pos[i], ts_ElasticEaseIn, fHudSprites[i].Position.AsVector,
                                                   VectorMake(x2, 20 + i * 65, 0), 3, (i - 1) / 5);

    if(aType = 2) or (aType = 4) then
      for i := 1 to 4 do
        AddTweenPVector(@Pos[i], ts_ElasticEaseIn, fHudSprites[i].Position.AsVector,
                                                   VectorMake(-35 + i * 95, y2, 0), 3, (i - 1) / 5);
  end;
end;

Procedure TfrmMain.OnCadencerProgress(Sender : TObject; const deltaTime, newTime : Double);
var
 i: integer;
 MPos: TPoint;
begin
  fTweener.Update(DeltaTime);
  for i := 1 to 4 do
    fHudSprites[i].position.SetPoint(Pos[i]);

  GetCursorPos(Mpos);
  MPos := fViewer.ScreenToClient(MPos);
  if IsKeyDown(vk_LButton) and not MousePressed then
  begin
    i := GetHudSpriteAtPos(mPos.x, mPos.y);
    if i <> -1 then
      StartTween(i);
  end;

  MousePressed := IsKeyDown(vk_LButton);
end;

end.
